/* utils function */
#include "utils.h"

/*****************************************************************************/
#if 0
#ifndef int64_t_C
#define int64_t_C(c)     (c ## LL)
#define uint64_t_C(c)    (c ## ULL)
#endif

#ifndef MAXINT64
#define MAXINT64 int64_t_C(0x7fffffffffffffff)
#endif

#ifndef MININT64
#define MININT64 int64_t_C(0x8000000000000000)
#endif

#define NOPTS_VALUE MININT64
#endif 

/*****************************************************************************/

void init_packet(Packet *pkt)
{
    pkt->pts   = gettime();////NOPTS_VALUE;
////    pkt->flags = 0;
//    pkt->stream_index = 0;
}

/**
 * Default packet destructor 
 */
static void destruct_packet(Packet *pkt)
{
    free(pkt->head);
    pkt->head = NULL; 
    pkt->data = NULL; 
    pkt->size = 0;
    pkt->data_size = 0;
}

/**
 * Allocate the payload of a packet and intialized its fields to default values.
 *
 * @param pkt packet
 * @param size wanted payload size
 * @return 0 if OK. AVERROR_xxx otherwise.
 */
int new_packet(Packet *pkt, int size)
{
    void *data = calloc(1,size+PKT_RSV_HDR);
//printf("new 0x%x\n", (int)data);
    if (!data)
        return ERROR_NOMEM;

    init_packet(pkt);
    pkt->head = data;
    pkt->data = pkt->head+PKT_RSV_HDR; 
    pkt->size = size;
    pkt->destruct = destruct_packet;
    return 0;
}

/**
 * Free a packet
 *
 * @param pkt packet to free
 */
void free_packet(Packet *pkt)
{
    if (pkt && pkt->destruct) {
	pkt->destruct(pkt);
    }
}


/* packet queue handling */
void packet_queue_init(PacketQueue *q)
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
    q->cond = SDL_CreateCond();
}


void packet_queue_end(PacketQueue *q)
{
    PacketList *pkt, *pkt1;

    for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
        pkt1 = pkt->next;
        free_packet(&pkt->pkt);
        free(pkt);
    }
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}

int packet_queue_put(PacketQueue *q, Packet *pkt)
{
    PacketList *pkt1;

    pkt1 = calloc(1,sizeof(PacketList));
    if (!pkt1)
        return ERROR_NOMEM;
        
    pkt1->pkt = *pkt;
    pkt1->next = NULL;

    SDL_LockMutex(q->mutex);

    if (!q->last_pkt)
        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++;
    q->size += pkt1->pkt.size;
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);
    SDL_UnlockMutex(q->mutex);
    return 0;
}

void packet_queue_abort(PacketQueue *q)
{
    SDL_LockMutex(q->mutex);
    q->abort_request = 1;    
    SDL_CondSignal(q->cond);
    SDL_UnlockMutex(q->mutex);
}
 
/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
int packet_queue_get(PacketQueue *q, Packet *pkt, int block)
{
    PacketList *pkt1;
    int ret;

    SDL_LockMutex(q->mutex);

    for(;;) {
        if (q->abort_request) {
            ret = -1;
            break;
        }
            
        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
            q->size -= pkt1->pkt.size;
            *pkt = pkt1->pkt;
            free(pkt1);
            ret = 1;
            break;
        } else if (!block) {
            ret = 0;
            break;
        } else {
            SDL_CondWait(q->cond, q->mutex);
        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}

void  packet_queue_flush(PacketQueue *q)
{
	int res;
	Packet pkt;
	do{
		res = packet_queue_get(q, &pkt, 0);
		free_packet(&pkt);
	}while(res > 0);
}

int64_t gettime(void)
{

    struct timeval tv;
    gettimeofday(&tv,NULL);
    return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
}

